package cn.apelx.shardingjdbc.config;

import cn.hutool.core.util.ReflectUtil;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import java.lang.reflect.Field;

/**
 * 没鸟用
 */
//@Component
public class IgnoreJPAReadOnlyTransactionBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof JpaRepositoryFactoryBean) {
       /*     RepositoryFactoryCustomizer customizer = new RepositoryFactoryCustomizer() {
                @Override
                public void customize(RepositoryFactorySupport repositoryFactory) {
                    repositoryFactory.addRepositoryProxyPostProcessor(new IgnoreJPAReadOnlyTransactionRepositoryProxyPostProcessor());
                }
            };*/
            //            ((RepositoryFactoryBeanSupport<?, ?, ?>) bean).addRepositoryFactoryCustomizer(customizer);

           IgnoreJPAReadOnlyTransactionRepositoryProxyPostProcessor processor = new IgnoreJPAReadOnlyTransactionRepositoryProxyPostProcessor();

            try {
                Field factoryField = RepositoryFactoryBeanSupport.class.getDeclaredField("factory");
                factoryField.setAccessible(true);
                RepositoryFactorySupport repositoryFactorySupport = (RepositoryFactorySupport) factoryField.get(bean);

                repositoryFactorySupport.addRepositoryProxyPostProcessor(processor);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return bean;
    }

    private static class IgnoreJPAReadOnlyTransactionRepositoryProxyPostProcessor implements RepositoryProxyPostProcessor {
        @Override
        public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
            Advisor[] advisors = factory.getAdvisors();
            TransactionInterceptor transactionInterceptor = null;
            for (Advisor advisor : advisors) {
                if (advisor != null && advisor.getAdvice() instanceof TransactionInterceptor) {
                    transactionInterceptor = (TransactionInterceptor) advisor.getAdvice();
                    break;
                }
            }
            if (transactionInterceptor != null) {
                TransactionAttributeSource transactionAttributeSource = transactionInterceptor.getTransactionAttributeSource();
                TransactionAttributeSource ignoreReadOnlyDelegate = (method, targetClass) -> {
                    TransactionAttribute transactionAttribute = transactionAttributeSource.getTransactionAttribute(method, targetClass);
                    if (transactionAttribute != null && transactionAttribute.isReadOnly()) {
                        return null;
                    }
                    return transactionAttribute;
                };
                transactionInterceptor.setTransactionAttributeSource(ignoreReadOnlyDelegate);
            }
        }
    }
}
